#include "Graphics.h"
#include <d3dx9.h>
#include "Window.h"
//---------------------------------------------------------------------------------------------//
Graphics::Graphics():
m_dxObject(NULL),
m_dxDevice(NULL),
m_pVertexObject(NULL),
m_lastTexture(NULL)
{
}
//---------------------------------------------------------------------------------------------//
bool Graphics::Init(HWND hwnd)
{
	m_dxObject = Direct3DCreate9(D3D_SDK_VERSION);
	
	if(!m_dxObject)
		return false;
	
	D3DPRESENT_PARAMETERS PresentParams;
	
	memset(&PresentParams, 0, sizeof(D3DPRESENT_PARAMETERS));
	
	PresentParams.Windowed = TRUE;				
	PresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
	PresentParams.EnableAutoDepthStencil = TRUE;
	PresentParams.AutoDepthStencilFormat = D3DFMT_D16;
	
	m_dxObject->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &PresentParams, &m_dxDevice);

	if (!m_vertexBuffer.Create(m_dxDevice))
		return false;

	if (!m_indexBuffer.Create(m_dxDevice))
		return false;
		
	SetMatrixMode(VIEW_MATRIX);
	LoadIdentity();

	SetMatrixMode(WORLD_MATRIX);
	LoadIdentity();

	D3DXMATRIX mat;

	//----------------------------------< Camera 3D >-----------------------------------
	D3DXMatrixPerspectiveFovLH(&mat, D3DX_PI / 4, (float)wWidth / (float)wHeight ,1,1000); 
	m_dxDevice->SetTransform(D3DTS_PROJECTION, &mat);

	//--------------------------------< Renderer States >-------------------------------
	m_dxDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
	m_dxDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
	m_dxDevice->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);
	//m_dxDevice->SetRenderState(D3DRS_AMBIENT,0xffffff);
	m_dxDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
	//m_dxDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
	m_dxDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	m_dxDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
	m_dxDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	m_dxDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
	m_dxDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
	m_dxDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
	m_dxDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
	m_dxDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);

	return true;
}
//---------------------------------------------------------------------------------------------//
void Graphics::Clear() 
{
	m_dxDevice->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0, 0, 0),1.0f,0);
}
//---------------------------------------------------------------------------------------------//
void Graphics::BeginScene()
{
	m_dxDevice->BeginScene();
}
//---------------------------------------------------------------------------------------------//
void Graphics::EndScene()
{
	m_dxDevice->EndScene();
}
//---------------------------------------------------------------------------------------------//
void Graphics::Present(HWND hwnd)
{
	m_dxDevice->Present(NULL, NULL, NULL, NULL);
	ValidateRect(hwnd, NULL);
}
//---------------------------------------------------------------------------------------------//
void Graphics::DeInit()
{
	m_dxDevice->Release();
	m_dxObject->Release();
}
//---------------------------------------------------------------------------------------------//
bool Graphics::DrawElements(
	USHORT vertexCount, D3DMeshVertex* vertices,
	USHORT indexCount, USHORT* indices,
	USHORT primCount, PRIM_TYPE primType)
{
	m_vertexBuffer.Bind();
	m_indexBuffer.Bind();

	m_indexBuffer.Draw(indices,indexCount);
	m_vertexBuffer.Draw(vertices,vertexCount,primCount);

	return true;	
}
//---------------------------------------------------------------------------------------------//
void Graphics::SetMatrixMode(MATRIX_MODES mode)
{
	m_currentMatrixMode = mode;
}
//---------------------------------------------------------------------------------------------//
void Graphics::SetTransform(D3DMATRIX & matrix)
{
	m_dxDevice->SetTransform(D3DTS_VIEW, & matrix);
}
//---------------------------------------------------------------------------------------------//
void Graphics::LoadIdentity()
{
	D3DXMatrixIdentity( &m_dxMatrix );

	switch(m_currentMatrixMode)
	{
	case WORLD_MATRIX:
		m_dxDevice->SetTransform(D3DTS_WORLD, & m_dxMatrix);
		break;
	case VIEW_MATRIX:
		{
			D3DXVECTOR3 dxEyePosition(0.0f, 0.0f, 0.0f);
			D3DXVECTOR3 dxLookPosition(0.0f, 0.0f, 0.0f);
			D3DXVECTOR3 dxUpVertex(0.0f, 1.0f, 0.0f);

			D3DXMatrixLookAtLH(& m_dxMatrix, & dxEyePosition, & dxLookPosition, & dxUpVertex);
			m_dxDevice->SetTransform(D3DTS_VIEW, & m_dxMatrix);
			break;
		}
	case PROYECTION_MATRIX:
		m_dxDevice->SetTransform(D3DTS_PROJECTION, & m_dxMatrix);
		break;
	}
}
//---------------------------------------------------------------------------------------------//
void Graphics::Scale(Vector3 scale)
{
	D3DXMatrixScaling( &m_dxMatrix, scale.x, scale.y , scale.z );

	switch(m_currentMatrixMode)
	{
	case WORLD_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_WORLD, & m_dxMatrix);
		break;
	case VIEW_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_VIEW, & m_dxMatrix);
		break;
	case PROYECTION_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_PROJECTION, & m_dxMatrix);
		break;
	}
}
//---------------------------------------------------------------------------------------------//
void Graphics::Translate(Vector3 translation)
{
	D3DXMatrixTranslation( &m_dxMatrix, translation.x, translation.y, translation.z );

	switch(m_currentMatrixMode)
	{
	case WORLD_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_WORLD, & m_dxMatrix);
		break;
	case VIEW_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_VIEW, & m_dxMatrix);
		break;
	case PROYECTION_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_PROJECTION, & m_dxMatrix);
		break;
	}
}
//---------------------------------------------------------------------------------------------//
void Graphics::Rotate(Vector3 rotation)
{
	D3DXMatrixRotationX( &m_dxMatrix, rotation.x );
	
	switch(m_currentMatrixMode)
	{
	case WORLD_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_WORLD, & m_dxMatrix);
		break;
	case VIEW_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_VIEW, & m_dxMatrix);
		break;
	case PROYECTION_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_PROJECTION, & m_dxMatrix);
		break;
	}

	D3DXMatrixRotationY( &m_dxMatrix, rotation.y);
	
	switch(m_currentMatrixMode)
	{
	case WORLD_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_WORLD, & m_dxMatrix);
		break;
	case VIEW_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_VIEW, & m_dxMatrix);
		break;
	case PROYECTION_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_PROJECTION, & m_dxMatrix);
		break;
	}

	D3DXMatrixRotationZ( &m_dxMatrix, rotation.z);

	switch(m_currentMatrixMode)
	{
	case WORLD_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_WORLD, & m_dxMatrix);
		break;
	case VIEW_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_VIEW, & m_dxMatrix);
		break;
	case PROYECTION_MATRIX:
		m_dxDevice->MultiplyTransform(D3DTS_PROJECTION, & m_dxMatrix);
		break;
	}
}
//---------------------------------------------------------------------------------------------//
Texture* Graphics::LoadTexture(std::wstring path, DWORD colorKey)
{
	D3DXIMAGE_INFO info;
	LPDIRECT3DTEXTURE9 tex;

	HRESULT hr = D3DXCreateTextureFromFileEx(
		m_dxDevice,
		path.c_str(),
		0,
		0,
		0,
		D3DUSAGE_DYNAMIC,
		D3DFMT_FROM_FILE,
		D3DPOOL_DEFAULT,
		D3DX_FILTER_NONE,
		D3DX_FILTER_NONE,
		colorKey,
		&info,
		NULL,
		&tex);

	if (hr == D3D_OK)
	{
		Texture* aux = new Texture();
		aux->data = tex;
		aux->height = info.Height;
		aux->width = info.Width;
		aux->path = path;
		
		return aux;
	}
	
	return NULL;
}
//---------------------------------------------------------------------------------------------//
void Graphics::SetTexture(Texture* pTexture)
{ 
	if (m_lastTexture != pTexture)
	{
		if (pTexture != NULL) 
		{
			m_dxDevice->SetTexture(0,pTexture->data);
		}
		else
		{
			m_dxDevice->SetTexture(0,NULL);
		}					

		m_lastTexture = pTexture;
	}
}
//---------------------------------------------------------------------------------------------//
bool Graphics::SetLights(D3DLIGHT9* light)
{
	SetMatrixMode(WORLD_MATRIX);
	LoadIdentity();

   return SUCCEEDED( m_dxDevice->SetLight( 0, light ) ) && 
		   SUCCEEDED( m_dxDevice->LightEnable( 0, TRUE ) );
}
//---------------------------------------------------------------------------------------------//
bool Graphics::SetMaterials(D3DMATERIAL9& material)
{
   return SUCCEEDED( m_dxDevice->SetMaterial(&material) );
}